package com.gitee.wsl.flowing.chain

import kotlinx.io.IOException
import timber.log.Timber


/**
 * 入口类
 *
 */

fun <Request,Response> sampleChain(request: Request,interceptorConfig: SampleChain<Request, Response>.()->Unit): SampleChain<Request, Response> {
    val chain = SampleChain<Request,Response>(request)
    interceptorConfig(chain)
    return chain
}

fun interface Interceptor<Request,Response> {
    @Throws(IOException::class)
    fun intercept(chain: Chain<Request, Response>): Response

    companion object {
        /**
         * Constructs an interceptor for a lambda. This compact syntax is most useful for inline
         * interceptors.
         *
         * ```
         * val interceptor = Interceptor { chain: Interceptor.Chain ->
         *     chain.proceed(chain.request())
         * }
         * ```
         */
        inline operator fun <Request,Response> invoke(crossinline block: (chain: Chain<Request, Response>) -> Response): Interceptor<Request, Response> =
            Interceptor { block(it) }
    }

    interface Chain<Request,Response> {
        fun request(): Request

        @Throws(IOException::class)
        fun proceed(request: Request): Response

        val context: ChainContext
    }
}

class SampleChain<Request,Response>(val originalRequest: Request,val context: ChainContext = ChainContext()) {

    internal val interceptors: MutableList<Interceptor<Request, Response>> = mutableListOf()

    fun addInterceptor(interceptor: Interceptor<Request, Response>) = apply {
        interceptors += interceptor
    }

     // Prefix with '-' to prevent ambiguous overloads from Java.
    inline fun addInterceptor(crossinline block: (chain: Interceptor.Chain<Request, Response>) -> Response) =
        addInterceptor(Interceptor { chain -> block(chain) })

    fun getResponseWithInterceptorChain(): Result<Response> {

        val chain = RealInterceptorChain(
            interceptors = interceptors,
            index = 0,
            request = originalRequest,
            context
        )

        try {
            return Result.success(chain.proceed(originalRequest))
        } catch (e: Exception) {
           Timber.d(e)
        }
        return Result.failure(RuntimeException("call exec false"))
    }

}


/**
 * A concrete interceptor chain that carries the entire interceptor chain: all application
 * interceptors, the OkHttp core, all network interceptors, and finally the network caller.
 *
 * If the chain is for an application interceptor then [exchange] must be null. Otherwise it is for
 * a network interceptor and [exchange] must be non-null.
 */
class RealInterceptorChain<Request,Response>(
    private val interceptors: List<Interceptor<Request, Response>>,
    private val index: Int,
    internal val request: Request,
    override val context: ChainContext
) : Interceptor.Chain<Request, Response> {

    private var calls: Int = 0

    internal fun copy(
        index: Int = this.index,
        request: Request = this.request,
    ) = RealInterceptorChain(interceptors, index, request,context)

    override fun request(): Request = request

    @Throws(IOException::class)
    override fun proceed(request: Request): Response {
        check(index < interceptors.size)

        calls++

        // Call the next interceptor in the chain.
        val next = copy(index = index + 1, request = request)
        val interceptor = interceptors[index]

        @Suppress("USELESS_ELVIS")
        val response = interceptor.intercept(next) ?: throw NullPointerException(
            "interceptor $interceptor returned null")

        return response
    }

}
